package cn.ruanyun.backInterface.modules.auctionCalendar.site.serviceimpl;

import cn.ruanyun.backInterface.common.constant.CommonConstant;
import cn.ruanyun.backInterface.common.enums.BooleanTypeEnum;
import cn.ruanyun.backInterface.common.enums.DayTimeTypeEnum;
import cn.ruanyun.backInterface.common.enums.OrderStatusEnum;
import cn.ruanyun.backInterface.common.utils.*;
import cn.ruanyun.backInterface.common.vo.PageVo;
import cn.ruanyun.backInterface.common.vo.Result;
import cn.ruanyun.backInterface.modules.auctionCalendar.site.dto.SiteDto;
import cn.ruanyun.backInterface.modules.auctionCalendar.site.mapper.SiteMapper;
import cn.ruanyun.backInterface.modules.auctionCalendar.site.pojo.Site;
import cn.ruanyun.backInterface.modules.auctionCalendar.site.service.ISiteService;
import cn.ruanyun.backInterface.modules.auctionCalendar.site.vo.*;
import cn.ruanyun.backInterface.modules.auctionCalendar.siteAuctionCalendar.mapper.SiteAuctionCalendarMapper;
import cn.ruanyun.backInterface.modules.auctionCalendar.siteAuctionCalendar.pojo.SiteAuctionCalendar;
import cn.ruanyun.backInterface.modules.auctionCalendar.sitePrice.mapper.SitePriceMapper;
import cn.ruanyun.backInterface.modules.auctionCalendar.sitePrice.pojo.SitePrice;
import cn.ruanyun.backInterface.modules.base.pojo.DataVo;
import cn.ruanyun.backInterface.modules.base.pojo.User;
import cn.ruanyun.backInterface.modules.base.service.mybatis.IUserService;
import cn.ruanyun.backInterface.modules.business.area.service.IAreaService;
import cn.ruanyun.backInterface.modules.business.comment.service.ICommentService;
import cn.ruanyun.backInterface.modules.business.goodCategory.entity.GoodCategory;
import cn.ruanyun.backInterface.modules.business.goodCategory.service.IGoodCategoryService;
import cn.ruanyun.backInterface.modules.business.itemAttrVal.service.IItemAttrValService;
import cn.ruanyun.backInterface.modules.business.order.mapper.OrderMapper;
import cn.ruanyun.backInterface.modules.business.order.pojo.Order;
import cn.ruanyun.backInterface.modules.business.order.service.IOrderService;
import cn.ruanyun.backInterface.modules.business.orderDetail.pojo.OrderDetail;
import cn.ruanyun.backInterface.modules.business.orderDetail.service.IOrderDetailService;
import cn.ruanyun.backInterface.modules.business.selectStore.service.ISelectStoreService;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.mchange.v2.holders.ThreadSafeIntHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import javax.annotation.Resource;


/**
 * 场地接口实现
 * @author fei
 */
@Slf4j
@Service
@Transactional
public class ISiteServiceImpl extends ServiceImpl<SiteMapper, Site> implements ISiteService {


    @Autowired
    private SecurityUtil securityUtil;

    @Autowired
    private IItemAttrValService iItemAttrValService;

    @Resource
    private SitePriceMapper sitePriceMapper;

    @Resource
    private SiteAuctionCalendarMapper siteAuctionCalendarMapper;

    @Resource
    private OrderMapper orderMapper;

    @Autowired
    private SiteMapper siteMapper;

    @Autowired
    private IGoodCategoryService goodCategoryService;

    @Autowired
    private IUserService userService;

    @Autowired
    private ICommentService commentService;

    @Autowired
    private IOrderDetailService orderDetailService;

    @Autowired
    private IAreaService areaService;

    @Autowired
    private ISelectStoreService selectStoreService;


    @Override
    public void insertOrderUpdateSite(Site site) {

        User user = userService.getById(securityUtil.getCurrUser().getId());

        if (ToolUtil.isEmpty(site.getCreateBy())) {

            site.setAreaId(user.getAreaId())
                    .setCreateBy(user.getId());
        }else {

            site.setUpdateBy(securityUtil.getCurrUser().getId());
        }
        this.saveOrUpdate(site);
    }

    @Override
    public void removeSite(String ids) {

        CompletableFuture.runAsync(() -> this.removeByIds(ToolUtil.splitterStr(ids)));
    }

    @Override
    public Result<List<SiteListVo>> getSiteList(String storeId) {

        return Optional.ofNullable(ToolUtil.setListToNul(this.list(Wrappers.<Site>lambdaQuery()
        .eq(Site::getCreateBy, storeId)
        .orderByDesc(Site::getCreateTime))))
        .map(sites -> new ResultUtil<List<SiteListVo>>().setData(sites.parallelStream().flatMap(site -> {

            SiteListVo siteListVo = new SiteListVo();
            ToolUtil.copyProperties(site, siteListVo);
            siteListVo.setSiteItemValue(iItemAttrValService.getItemAttrValVo(site.getSiteItemValue()))
                    .setSitePic(Optional.ofNullable(ToolUtil.setListToNul(ToolUtil.splitterStr(site.getSitePics())))
                    .map(pics -> pics.get(0)).orElse("-"));

            return Stream.of(siteListVo);
        }).collect(Collectors.toList()), "获取门店场地信息成功！"))
        .orElse(new ResultUtil<List<SiteListVo>>().setErrorMsg(201, "暂无数据！"));
    }

    /**
     * 查询场地详情
     *
     * @param id id
     * @return SiteDetailVo
     */
    @Override
    public Result<SiteDetailVo> getSiteDetail(String id) {

        return Optional.ofNullable(this.getById(id)).map(site -> {

            SiteDetailVo siteDetailVo = new SiteDetailVo();
            ToolUtil.copyProperties(site,siteDetailVo);
            siteDetailVo.setSiteItemValues(iItemAttrValService.getItemAttrVals(site.getSiteItemValue()))
                    .setSitePics(ToolUtil.splitterStr(site.getSitePics()));

            return new ResultUtil<SiteDetailVo>().setData(siteDetailVo, "获取场地信息成功！");
        }).orElse(new ResultUtil<SiteDetailVo>().setErrorMsg(201, "暂无场地信息"));
    }

    @Override
    public Result<DataVo<BackSiteListVo>> getBackSiteListVo(PageVo pageVo) {

        Page<Site> sitePage = this.page(PageUtil.initMpPage(pageVo), Wrappers.<Site>lambdaQuery()
                .eq(Site::getCreateBy, securityUtil.getCurrUser().getId())
        .orderByDesc(Site::getCreateTime));

        if (ToolUtil.isEmpty(sitePage.getRecords())) {

            return new ResultUtil<DataVo<BackSiteListVo>>().setErrorMsg(201, "暂无数据！");
        }

        DataVo<BackSiteListVo> result = new DataVo<>();

        result.setDataResult(sitePage.getRecords().parallelStream().flatMap(site -> {

            BackSiteListVo backSiteListVo = new BackSiteListVo();

            ToolUtil.copyProperties(site, backSiteListVo);
            backSiteListVo.setSiteItemValue(iItemAttrValService.getItemAttrValVo(site.getSiteItemValue()));
            backSiteListVo.setCategoryName(goodCategoryService.getGoodCategoryName(site.getCategoryId()));
            backSiteListVo.setSitePics(Optional.ofNullable(site.getSitePics())
            .map(ToolUtil::splitterStr)
            .orElse(null));

            return Stream.of(backSiteListVo);
        }).collect(Collectors.toList())).setTotalSize(sitePage.getTotal())
                .setCurrentPageNum(sitePage.getCurrent())
                .setTotalPage(sitePage.getPages());

        return new ResultUtil<DataVo<BackSiteListVo>>().setData(result, "获取场所数据成功！");
    }

    /**
     * App按分类获取场地列表
     * @param categoryId 分类id
     * @return
     */
    @Override
    public Result<List<SiteListVo>> appGetCategorySiteList(String categoryId) {

        return Optional.ofNullable(ToolUtil.setListToNul(this.list(Wrappers.<Site>lambdaQuery()
                .eq(ToolUtil.isNotEmpty(categoryId),Site::getCategoryId, categoryId)
                .orderByDesc(Site::getCreateTime))))
                .map(sites -> new ResultUtil<List<SiteListVo>>().setData(sites.parallelStream().flatMap(site -> {

                    SiteListVo siteListVo = new SiteListVo();
                    ToolUtil.copyProperties(site, siteListVo);
                    siteListVo.setSiteItemValue(iItemAttrValService.getItemAttrValVo(site.getSiteItemValue()))
                            .setSitePic(Optional.ofNullable(ToolUtil.setListToNul(ToolUtil.splitterStr(site.getSitePics())))
                                    .map(pics -> pics.get(0)).orElse("-"));

                    return Stream.of(siteListVo);
                }).collect(Collectors.toList()), "App按分类获取场地列表成功！"))
                .orElse(new ResultUtil<List<SiteListVo>>().setErrorMsg(201, "暂无数据！"));
    }

    /**
     * 查询场地某个时间段是否有档期时间
     * @param siteId  场地id
     * @param scheduleTime  时间
     * @return
     */
    @Override
    public List<SiteDetailTimeVO> getSiteDetailTime(String siteId, String scheduleTime) {

        List<SiteDetailTimeVO> siteDetailTimeVOS = new ArrayList<>();

        //1.先设置俩个时间段，上午和下午，以及默认价格
        SiteDetailTimeVO siteDetailTimeVO = new SiteDetailTimeVO();
        siteDetailTimeVO.setDayTimeType(DayTimeTypeEnum.A_M).setStatus(1).setSitePrice(Optional.ofNullable(this.getOne(Wrappers.<Site>lambdaQuery()
                .eq(Site::getId,siteId).eq(Site::getDelFlag,CommonConstant.STATUS_NORMAL)
        )).map(Site::getSitePrice).orElse(null));
        siteDetailTimeVOS.add(siteDetailTimeVO);


        SiteDetailTimeVO siteDetailTimeVO1 = new SiteDetailTimeVO();
        siteDetailTimeVO1.setDayTimeType(DayTimeTypeEnum.P_M).setStatus(1).setSitePrice(Optional.ofNullable(this.getOne(Wrappers.<Site>lambdaQuery()
                .eq(Site::getId,siteId).eq(Site::getDelFlag,CommonConstant.STATUS_NORMAL)
        )).map(Site::getSitePrice).orElse(null));
        siteDetailTimeVOS.add(siteDetailTimeVO1);


        //2.查看特殊节日的价格
       List<SitePrice> sitePrices =  sitePriceMapper.selectList(new QueryWrapper<SitePrice>().lambda()
                    .eq(SitePrice::getScheduleTime,scheduleTime)
                    .eq(SitePrice::getSiteId,siteId)
                    .eq(SitePrice::getDelFlag,CommonConstant.STATUS_NORMAL)
       );

       //3.查看是否有档期
        List<SiteAuctionCalendar>  siteAuctionCalendars = siteAuctionCalendarMapper.selectList(new QueryWrapper<SiteAuctionCalendar>().lambda()
                .eq(SiteAuctionCalendar::getNoScheduleTime,scheduleTime)
                .eq(SiteAuctionCalendar::getSiteId,siteId)
                .eq(SiteAuctionCalendar::getDelFlag,CommonConstant.STATUS_NORMAL)

        );


        for (SiteDetailTimeVO detailTimeVO : siteDetailTimeVOS) {

            //2.1 如果有特殊的价格就重新赋值价格
            for (SitePrice sitePrice : sitePrices) {

                if(detailTimeVO.getDayTimeType().equals(sitePrice.getDayTimeType())){

                    detailTimeVO.setSitePrice(sitePrice.getSitePrice());
                }

            }

            //3.1 如果没有档期时间就赋值状态0 == 无
          for (SiteAuctionCalendar siteAuctionCalendar : siteAuctionCalendars) {

                if(detailTimeVO.getDayTimeType().equals(siteAuctionCalendar.getDayTimeType())){

                    detailTimeVO.setStatus(0);
                }

            }

            //4.判断订单被购买
            Optional.ofNullable(orderMapper.selectOne(Wrappers.<Order>lambdaQuery()
                    .eq(Order::getDayTimeType,detailTimeVO.getDayTimeType())
                    .eq(Order::getSiteId,siteId)
                    .eq(Order::getScheduleAppointment,scheduleTime)
                    .ge(Order::getOrderStatus, OrderStatusEnum.PRE_SEND)
                    .ne(Order::getOrderStatus, OrderStatusEnum.RETURN_FINISH)
                    .ne(Order::getOrderStatus, OrderStatusEnum.CANCEL_ORDER)
                    .last("limit 1")
            )).ifPresent(order -> { detailTimeVO.setStatus(0); });


        }


        return siteDetailTimeVOS;
    }

    @Override
    public Result<DataVo<AppSiteListVo>> getAppSiteList(SiteDto siteDto, PageVo pageVo) {


        //城市名称
        String areaId = areaService.getIdByAreaName(siteDto.getAreaName());

        if (StringUtils.isEmpty(areaId)) {

            return new ResultUtil<DataVo<AppSiteListVo>>().setErrorMsg(201, "暂无数据！");
        }

        LambdaQueryWrapper<Site> siteWrapper = Wrappers.<Site>lambdaQuery()
                //按照分类筛选
                .in(Site::getCategoryId, getAllCategory(siteDto.getCategoryId()))

                //按照价格筛选
                .ge(ToolUtil.isNotEmpty(siteDto.getPriceLow()), Site::getSitePrice, siteDto.getPriceLow())

                //按照价格筛选
                .le(ToolUtil.isNotEmpty(siteDto.getPriceHigh()), Site::getSitePrice, siteDto.getPriceHigh())

                //按照区域筛选
                .eq(Site::getAreaId, areaId)
                //时间排序
                .orderByDesc(Site::getCreateTime);

        //是否推荐
        if (ToolUtil.isNotEmpty(siteDto.getRecommend())) {

            if (siteDto.getRecommend() == 1) {

                siteWrapper.eq(Site::getRecommend, BooleanTypeEnum.YES);
            }
        }

        //是否按照价格排序
        if (ToolUtil.isNotEmpty(siteDto.getPriceSort())) {

            if (siteDto.getPriceSort() == 1) {

                siteWrapper.orderByDesc(Site::getSitePrice);
            }else {
                siteWrapper.orderByAsc(Site::getSitePrice);
            }
        }

        Page<Site> sitePage = this.page(PageUtil.initMpPage(pageVo), siteWrapper);

       return Optional.ofNullable(ToolUtil.setListToNul(sitePage.getRecords())).map(sites -> {

            List<AppSiteListVo> appSiteListVos = sites.parallelStream().flatMap(site -> {

                AppSiteListVo appSiteListVo = new AppSiteListVo();

                //场地介绍图片第一张
                appSiteListVo.setSitePics(Optional.ofNullable(ToolUtil.setListToNul(ToolUtil.splitterStr(site.getSitePics())))
                .map(pics -> pics.get(0)).orElse(null));

                //店铺信息
                Optional.ofNullable(userService.getById(site.getCreateBy())).ifPresent(user -> {

                    appSiteListVo.setStoreAvatar(user.getAvatar()).setStoreName(user.getNickName())
                            .setAreaId(user.getAreaId())
                            .setDistance(DistanceUtil.getDistance(siteDto.getLongitude(), siteDto.getLatitude(),
                                    user.getLongitude(), user.getLatitude())).setStoreType(goodCategoryService.judgeStoreType(user)).setStoreId(user.getId());

                    //点评数
                    appSiteListVo.setCommentNum(commentService.getCommentByStore(user.getId()))
                            .setStarLevel(commentService.getGoodScore(site.getId()));

                    //销售量
                    appSiteListVo.setVolume(orderDetailService.getGoodSalesVolume(site.getId()));
                });

                ToolUtil.copyProperties(site, appSiteListVo);
                return Stream.of(appSiteListVo);
            }).collect(Collectors.toList());


            //筛选

            //1.销量升序
           if (ToolUtil.isNotEmpty(siteDto.getVolumeSort())) {

               if (siteDto.getVolumeSort() == 1) {

                 appSiteListVos = appSiteListVos.parallelStream().sorted(Comparator.comparing(AppSiteListVo::getVolume))
                           .collect(Collectors.toList());
               }else {

                   //1.销量降序
                   appSiteListVos = appSiteListVos.parallelStream().sorted(Comparator.comparing(AppSiteListVo::getVolume).reversed())
                           .collect(Collectors.toList());
               }
           }


            //距离排序
           if (ToolUtil.isNotEmpty(siteDto.getDistanceSort())) {

               if (siteDto.getDistanceSort() == 1) {

                   appSiteListVos = appSiteListVos.parallelStream().sorted(Comparator.comparing(AppSiteListVo::getDistance))
                           .collect(Collectors.toList());
               }else {

                   appSiteListVos = appSiteListVos.parallelStream().sorted(Comparator.comparing(AppSiteListVo::getDistance))
                           .collect(Collectors.toList());
               }
           }


           //出去冻结商品
           appSiteListVos = appSiteListVos.parallelStream().filter(appSiteListVo -> selectStoreService.judgeFreezeStore(appSiteListVo.getStoreId()))
                   .collect(Collectors.toList());


           DataVo<AppSiteListVo> result = new DataVo<>();
           result.setDataResult(appSiteListVos)
                   .setTotalSize(sitePage.getTotal())
                   .setTotalPage(sitePage.getPages())
                   .setCurrentPageNum(sitePage.getCurrent());

           return new ResultUtil<DataVo<AppSiteListVo>>().setData(result, "获取app场地数据成功！");

        }).orElse(new ResultUtil<DataVo<AppSiteListVo>>().setErrorMsg(201, "暂无数据！"));

    }

    @Override
    public Result<Object> updateSiteRecommend(String id) {


        return Optional.ofNullable(this.getById(id)).map(site -> {

            Integer siteRecomment = getSiteRecomment();

            if (site.getRecommend().equals(BooleanTypeEnum.YES)) {

                site.setRecommend(BooleanTypeEnum.NO);
            }else {

                if (siteRecomment > 4) {

                    return new ResultUtil<>().setErrorMsg(204, "推荐场地不能大于5个");
                }

                site.setRecommend(BooleanTypeEnum.YES);
            }

            this.updateById(site);

            return new ResultUtil<>().setSuccessMsg("更新场地推荐状态成功！");
        }).orElse(new ResultUtil<>().setErrorMsg(201, "暂无数据"));
    }

    /**
     * 修改状态
     *
     * @param id id
     * @return Object
     */
    @Override
    public Result<Object> putAwaySite(String id) {

        return Optional.ofNullable(this.getById(id)).map(site -> {

            if (BooleanTypeEnum.YES.equals(site.getPutAway())) {

                site.setPutAway(BooleanTypeEnum.NO);
                this.updateById(site);
            }else {

                site.setPutAway(BooleanTypeEnum.YES);
                this.updateById(site);
            }

            return new ResultUtil<>().setSuccessMsg("更新上下架成功！");
        }).orElse(new ResultUtil<>().setErrorMsg(201, "当前场地不存在！"));

    }


    public List<String> getAllCategory(String categoryId) {

        return Optional.ofNullable(ToolUtil.setListToNul(goodCategoryService.list(Wrappers.<GoodCategory>lambdaQuery()
        .eq(GoodCategory::getParentId, categoryId))))
        .map(goodCategories -> goodCategories.parallelStream().map(GoodCategory::getId)
        .collect(Collectors.toList()))
        .orElse(Collections.singletonList(categoryId));
    }


    /**
     * 获取推荐的数量
     * @return 推荐的数量
     */
    public Integer getSiteRecomment() {

        return this.count(Wrappers.<Site>lambdaQuery()
                .eq(Site::getRecommend, BooleanTypeEnum.YES)
                .eq(Site::getCreateBy, securityUtil.getCurrUser().getId()));

    }
}